#include "stdafx.h"
#include "CppUnitTest.h"

#include <BuilderHelper.h>


using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace TestSuperficies
{
	TEST_CLASS(TestBuilderHelper)
	{
	public:
		TEST_METHOD(TestBuilderHelperCreacion) {
			// Arrange
			const unsigned int cantPtsHorizontal = 3;
			const unsigned int cantPtsVertical = 2;
			const unsigned int cantTotalPuntos = cantPtsVertical * cantPtsHorizontal;
			const unsigned int cantTotalIndices = 6 * (cantPtsVertical -1) * (cantPtsHorizontal -1);

			std::vector< glm::vec3 > vertices;
			for (unsigned int i = 0; i < cantTotalPuntos; ++i) vertices.push_back( glm::vec3(0.0f, 0.0f, 0.0f) );

			// Act
			BuilderHelper bh(0.0f, 1.0f);
			std::vector< glm::vec3 > vNormales = bh.buildNormales(cantPtsHorizontal, vertices);
			std::vector< unsigned int > vIndices = bh.buildIndexBuffer(cantPtsHorizontal, cantPtsVertical);
			std::vector< glm::vec2 > vCoordsTextura = bh.buildCoordsTextura(cantPtsHorizontal, cantPtsVertical);

			// Assert
			Assert::AreEqual(cantTotalPuntos, vNormales.size(), L"La cantidad de normales no coincide con lo esperado");
			Assert::AreEqual(cantTotalIndices, vIndices.size(), L"No coincide la cantidad de indices con los esperados");
			Assert::AreEqual(cantTotalPuntos, vCoordsTextura.size(), L"La cantidad de coordenadas de textura obtenidas no es igual a la cantidad esperada");
		}


		TEST_METHOD(TestBuilderHelperNormales){
			// Arrange
			std::vector< glm::vec3 > vec;
			vec.push_back( glm::vec3(1.0f, 1.0f, 1.0f) );
			vec.push_back( glm::vec3(0.0f, 1.0f, 0.0f) );
			vec.push_back( glm::vec3(-1.0f, 1.0f, -1.0f) );

			vec.push_back( glm::vec3(1.0f, -1.0f, 1.0f) );
			vec.push_back( glm::vec3(0.0f, -1.0f, 0.0f) );
			vec.push_back( glm::vec3(-1.0f, -1.0f, -1.0f) );

			glm::vec3 normalEsperada(1.0f, 0.0f, -1.0f);
			normalEsperada = glm::normalize(normalEsperada);

			// Act
			BuilderHelper bh(0.0f, 1.0f);
			std::vector< glm::vec3 > vNormales = bh.buildNormales(3, vec);

			// Assert
			// Todas las normales tienen el mismo valor
			for (auto it = vNormales.cbegin(); it != vNormales.cend(); ++it){
				glm::vec3 pt = *it;
				Assert::AreEqual(normalEsperada.x, pt.x, L"No coincide la coordenada 'X' de la normal");
				Assert::AreEqual(normalEsperada.y, pt.y, L"No coincide la coordenada 'Y' de la normal");
				Assert::AreEqual(normalEsperada.z, pt.z, L"No coincide la coordenada 'Z' de la normal");
			}
		}


		TEST_METHOD(TestBuilderHelperIndices){
			// Arrange
			BuilderHelper bh(0.0f, 1.0f);

			// Act
			std::vector<unsigned int> vIndices = bh.buildIndexBuffer(3, 2);

			// Assert
			Assert::AreEqual(0u, vIndices[0], L"No coincide el indice '0'");
			Assert::AreEqual(1u, vIndices[1], L"No coincide el indice '1'");
			Assert::AreEqual(3u, vIndices[2], L"No coincide el indice '2'");

			Assert::AreEqual(1u, vIndices[3], L"No coincide el indice '3'");
			Assert::AreEqual(4u, vIndices[4], L"No coincide el indice '4'");
			Assert::AreEqual(3u, vIndices[5], L"No coincide el indice '5'");

			Assert::AreEqual(1u, vIndices[6], L"No coincide el indice '6'");
			Assert::AreEqual(2u, vIndices[7], L"No coincide el indice '7'");
			Assert::AreEqual(4u, vIndices[8], L"No coincide el indice '8'");

			Assert::AreEqual(2u, vIndices[9], L"No coincide el indice '9'");
			Assert::AreEqual(5u, vIndices[10], L"No coincide el indice '10'");
			Assert::AreEqual(4u, vIndices[11], L"No coincide el indice '11'");
		}


		TEST_METHOD(TestBuilderHelperCoordsTextura){
			// Arrange
			const float limInferior = 0.0f;
			const float limSuperior = 1.0f;
			const unsigned int cantPtsVertical = 2;
			const unsigned int cantPtsHorizontal = 3;

			const float pasoVertical = (limSuperior - limInferior) / (cantPtsVertical -1);
			const float pasoHorizontal = (limSuperior - limInferior) / (cantPtsHorizontal -1);

			// Act
			BuilderHelper bh(limInferior, limSuperior);
			std::vector<glm::vec2> vCoordsTextura = bh.buildCoordsTextura(cantPtsHorizontal, cantPtsVertical);

			// Assert
			for (unsigned int j = 0; j < cantPtsVertical; ++j){
				const float y = limInferior + j * pasoVertical;

				for (unsigned int i = 0; i < cantPtsHorizontal; ++i){
					const float x = limInferior + i * pasoHorizontal;
					const unsigned int pos = i + j * cantPtsHorizontal;

					Assert::AreEqual(x, vCoordsTextura[pos].x, L"No coincide la coordenada de textura 'X'");
					Assert::AreEqual(y, vCoordsTextura[pos].y, L"No coincide la coordenada de textura 'Y'");
				}
			}
		}


		// Este esta hecho especialmente para validar que las normales esten bien orientadas
		TEST_METHOD(TestHelperNormalesSentido){
			// Arrange
			std::vector< glm::vec3 > vec;
			vec.push_back( glm::vec3(1.0f, -1.0f, 1.0f) );
			vec.push_back( glm::vec3(1.0f, 0.0f, 1.0f) );
			vec.push_back( glm::vec3(1.0f, 1.0f, 1.0f) );

			vec.push_back( glm::vec3(1.0f, -1.0f, -1.0f) );
			vec.push_back( glm::vec3(1.0f, 0.0f, -1.0f) );
			vec.push_back( glm::vec3(1.0f, 1.0f, -1.0f) );

			glm::vec3 normalEsperada(1.0f, 0.0f, 0.0f);

			// Act
			BuilderHelper bh(0.0f, 1.0f);
			std::vector< glm::vec3 > vNormales = bh.buildNormales(3, vec);

			// Assert
			// Todas las normales tienen el mismo valor
			for (auto it = vNormales.cbegin(); it != vNormales.cend(); ++it){
				Assert::AreEqual( normalEsperada.x, (*it).x, L"No coincide la normal en X" );
				Assert::AreEqual( normalEsperada.y, (*it).y, L"No coincide la normal en Y" );
				Assert::AreEqual( normalEsperada.z, (*it).z, L"No coincide la normal en Z" );
			}
		}

	};
}